import 'dart:math';

import 'package:eshi/app/Extension.dart';
import 'package:eshi/app/shi/data/HistoryMarks.dart';
import 'package:eshi/app/shi/data/HistoryPoint.dart';
import 'package:eshi/app/shi/data/SearchResult.dart';
import 'package:eshi/app/shi/data/parse/IndentParser.dart';
import 'package:eshi/app/shi/data/parse/TxtPointParser.dart';
import 'package:eshi/app/shi/data/parse/XrlParser.dart';
import 'package:eshi/app/shi/data/tabtxt_history.dart';
import 'package:eshi/main.dart';


/// 历史数据类 
class History {
  int id = 0;
  String name = "";
  /// 这段历史的开始时间
  int startTime=0;
  /// 这段历史的结束时间
  int endTime=0;
  /// 历史关键点 列表
  List<HistoryPoint> data=[];
  String coverPage="";
  XrlParser? xrl;
  var _showMode = 0;  //0 自动 1 单页 2 单页多tab 3 多页多tab
  var _timeDesc = true; //倒叙排列 
  int get showMode => _showMode;
  String  defaultPath=""; //默认打开路径 
  get defaultPoint {
     if(defaultPath.isNotEmpty ){
        return data.firstWhere((test) => defaultPath.startsWith(test.name) );
     } 
     if(coverPage.isNotEmpty) {
      var rt= HistoryPoint.fromStringData("序",coverPage,isSingle:true)
      ..index=-1
      ..history=this;
      return rt;
     }
     return data.first;
  }
  set showMode(v){
    _showMode = v;
    if(this is TabTxtHistory) {
      TabTxtHistory.loadContent(name).then((text){
        TxtPointParser.parse(
          text,
          this as TabTxtHistory,
          name:name
          );
      });
    }
  }
  Map<String,HistoryMarks> marks ={};
  void addMark(String key, List<String> words) {
    var map = HistoryMarks.values.asNameMap();
    if(map.containsKey(key)) {
      for (var w in words) {
        marks[w] = map[key]!;
      }
    }
    //删除的
    if(key == "delete"){
      for(final w in words) {
        marks.remove(w);
      }
    }
    //绝对的
    if(key == "absValue"){
      marks.clear();
      for (var line in words) {
        var a = line.split(RegExp("[:,]"));
        addMark(a[0],a.sublist(1));
      }
    }
  }
  //用到的文件
  List<String> get useAssets{
    List<String> rt = [];
    // ignore: avoid_function_literals_in_foreach_calls
    data.forEach((p) => rt.addAll(p.useAssets));
    return rt;
  }

  void findMark(data, Null Function(dynamic type, String text,{String comment}) onFindOne){
      //初始化解析器
      if(xrl==null){
        xrl = XrlParser(marks.keys);
        xrl?.addkey("img.");
        // xrl?.addkey("http://");
        xrl?.addkey("https://");
        // ignore: avoid_function_literals_in_foreach_calls
        HistoryMarks.values.forEach((e) => xrl?.addkey("${e.name}.") );
      }
      var isIndent = IndentParser.isNode(data);
      if(!isIndent){
        //不解析层次关系
        _xrlParseText(data,onFindOne);
      }else{
        //文本扔回对象实现分层效果
        var indent = IndentElement(data);
        for (var v in indent.children) {
          _rCallIndent(v,onFindOne);
        }
      }
  }
  //根据关键字标识文本
  _xrlParseText(String text, Null Function(dynamic type, String text,{String comment}) onFindOne,{IndentElement? indent}){
      var partCount = 0;
      var comment  = (indent!=null) ? indent.comment : '';
      xrl!.parse(text,(key){
        var isLineEnd = key.endsWith("\n");
        if(partCount==0 && !isLineEnd){
           onFindOne("rowStart",comment);
        }
        if(key.endsWith(".")){
            var name=xrl!.nextWord();
            onFindOne(key.substring(0,key.length-1),name);
        }else if(key.endsWith("://")){
          var uri=xrl!.nextWord();
          onFindOne("uri",key+uri);
        }else if(marks.containsKey(key)){
            onFindOne(marks[key]!,key);
        }else {
            onFindOne("text",isLineEnd ? key.trimRight():key, comment: comment);
        }

        if(isLineEnd){
          if(partCount>0){
            onFindOne("rowEnd","");
          }
          partCount=0;
          return;
        }

        partCount++;
      });
  }
  //递归调用缩进
  _rCallIndent(Map<String,dynamic> data, Null Function(dynamic type, String text,{String comment}) onFindOne){
      var indent = IndentElement(data);
      if(indent.children.isNotEmpty){
            onFindOne("child",indent.content);
            for (var v in indent.children) {
                _rCallIndent(v, onFindOne);
            }
            onFindOne("child","");
      }else{
        _xrlParseText(indent.content,onFindOne,indent:indent);
      }
  }

  
  /// 初始化数据
  void initData(List<HistoryPoint> dataOriginal){
    dataOriginal.sort((a,b){ 
      return a.startTime.compareTo(b.startTime);
    });
    
    data  = _timeDesc ? dataOriginal.reversed.toList() : dataOriginal;
    //非日期还原排序 
    if(dataOriginal.first.startTime == dataOriginal.first.endTime){
      data = dataOriginal; 
    }
    data.forEachIndexed((i,p){
      p.index =i;
    });
    if(data.isNotEmpty){
      startTime = min( data.first.startTime,data.last.startTime);
      endTime = max(data.first.startTime, data.last.startTime);
    }
    data;
  }
  String _config="";

  set config(String str){
    if(str.contains("单页")) _showMode =1;
    if(str.contains("多页")) _showMode =2;
    if(str.contains("时间轴")) _showMode =3;
    _config = str;
  }


  /// 通过缩进的tab数据来初始化data
  void initDataByTableText(String code,{String name="",void Function(HistoryPoint point)? createPointBefore}) {
      var hashArray = IndentParser.encode(code);
      List<HistoryPoint> datas=[];
      final ie = IndentElement(hashArray);
      final minDepth = ie.minDepth;
      //节点名
      if(name.isNotEmpty) hashArray["content"] = name;
      //头部注释
      if(ie.comment.isNotEmpty){
        config = ie.comment;
      }
      //尾部索引 
      if(ie.children.last["content"]=="引用"){
        datas.add(HistoryPoint(hashArray["children"].removeLast(),isSingle: false));
      }
      var mode = showMode;
      if(mode==0){
        //数据的最小深度
        if(minDepth==1){ //肯定是单页
            mode =1;
        }else if(ie.maxDepth == 2){
            mode =2;
        }else{ 
            mode =3;
        }
      }  

      switch(mode){
        //数据的最小深度
        case 1: //肯定是单页
            var point = HistoryPoint(hashArray,name:name,isSingle:true);
            datas.add(point);
            break;
        case 2:
              var point = HistoryPoint.fromIndentData(name, hashArray);
              datas.add(point); 
              break;
        default:
            for(var item in hashArray['children']){
              var one = HistoryPoint(item);
              datas.add(one);
            }
      }
      
      for(final one in datas){
        if(createPointBefore!=null){
          createPointBefore(one);
        }
        onPointCreate(one);
        one.history = this;
      }

      datas.removeWhere((one) => !one.enable);
      
      initData(datas);
  }

  onPointCreate(HistoryPoint one){}

  String get head{
      var rt = "";
      if(coverPage.isNotEmpty){
        rt= "序\n${coverPage.split("\n").map((v){
          return IndentParser.sp+v;
        }).join("\n")}\n";
      }else{
        rt= "";
      }
      return "$_config$rt\n";
  }

  String get floor{
    if(marks.isEmpty) return "";
    Map<String,List<String>> marksGroup ={};
    for(var p in marks.entries){
      if(!marksGroup.containsKey(p.value.name)) marksGroup[p.value.name]= [];
      marksGroup[p.value.name]?.add(p.key);
    }
    var rt="\n引用\n";
    marksGroup.forEach((k,v){
        rt+="${IndentParser.sp}$k\n";
        rt+="${IndentParser.sp*2}${v.join(",")}\n";
    });
    
    return rt;
  }

  @override
  toString(){
    String doc = head;
    for(HistoryPoint point in data){
      if(point.enable) {
        doc+= point.sourceCode();
      }
    }
    doc+=floor;
    return doc;
  }
  reload(String name) async {
    mainWidgetKey.currentState?.changeHistory(await TabTxtHistory.load(name));
  }
  /// 保存
  void save({HistoryPoint? point}) {
    TabTxtHistory.update(name,toString());
    reload(point!=null ? "$name.${point.name}" : name);
  }

  
  //文章内容搜索 
  int searchKey(String key) {
      HistorySearchResult.searchResult=[];
      var sum =0;
      for (var point in data) {
          final List<HistoryPointSearchResult> result = point.searchKey(key);
          final size = result.length;
          sum +=size;
          result.forEachIndexed((i,res){
            HistorySearchResult.add(point,res);
          });
      }
      return sum;
  }
}
